﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Reflection;

namespace WyUnity.Utility.ExtentionMethods
{
    /// <summary>
    /// Generic extensions dealing with objects
    /// </summary>
    public static class GenericObjectExtensions
    {
        #region Functions

        #region If

        /// <summary>
        /// 判断对象是否满足条件，如果满足，返回自身。否则，返回defaultValue
        /// </summary>
        public static T If<T>(this T obj, Predicate<T> predicate, T defaultValue = default(T))
        {
            if (obj == null)
                return defaultValue;
            return predicate(obj) ? obj : defaultValue;
        }

        #endregion

        #region NotIf

        /// <summary>
        /// 判断对象是否不满足条件，不满足则返回自身，否则返回默认值。
        /// </summary>
        public static T NotIf<T>(this T obj, Predicate<T> predicate, T defaultValue = default(T))
        {
            if (obj == null)
                return defaultValue;
            return predicate(obj) ? defaultValue : obj;
        }

        #endregion

        #region Return

        /// <summary>
        /// 判定一个对象自身是否为空和执行的结果是否为空，如果是，则返回默认值
        /// </summary>
        public static R Return<T, R>(this T obj, Func<T, R> function, R defaultValue = default(R))
        {
            if (obj == null)
                return defaultValue;
            R returnValue = function(obj);
            return returnValue == null ? defaultValue : returnValue;
        }

        #endregion

        #region Chain

        /// <summary>
        /// 链式操作（执行某个操作后返回自身）
        /// </summary>
        public static T Chain<T>(this T obj, Action<T> action)
        {
            action(obj);
            return obj;
        }

        //		/// <summary>
        //		/// 链式操作（执行某个操作后返回结果）
        //		/// </summary>
        //		public static R Chain<T, R>(this T obj, Func<T, R> function)
        //		{
        //			return function(obj);
        //		}

        #endregion

        #region Do

        /// <summary>
        /// 链式操作（执行某个操作后返回自身），如果对象或action为空，则使用默认值，此时将跳过action
        /// </summary>
        public static T Do<T>(this T obj, Action<T> action, T defaultValue = default(T))
        {
            if (obj == null || action == null)
                return defaultValue;
            return obj.Chain(action);
        }

        //		/// <summary>
        //		/// 链式操作（执行某个操作后返回结果），如果对象或function为空，则使用默认值，此时将跳过function
        //		/// </summary>
        //		public static R Do<T, R>(this T obj, Func<T, R> function, R defaultValue = default(R))
        //		{
        //			if (obj == null || function == null)
        //				return defaultValue;
        //			return obj.Chain(function);
        //		}

        #endregion

        #region Execute

        /// <summary>
        /// 执行一个操作，当失败(发生异常)时重试若干次
        /// </summary>
        public static T Execute<T>(this Func<T> function, int attempts = 3, int retryDelay = 0, int timeOut = int.MaxValue)
        {
            function.ThrowIfNull("Function");
            Exception holder = null;
            long start = System.Environment.TickCount;
            while (attempts > 0)
            {
                try
                {
                    return function();
                }
                catch (Exception e) { holder = e; }
                if (System.Environment.TickCount - start > timeOut)
                    break;
                Thread.Sleep(retryDelay);
                --attempts;
            }
            throw holder;
        }

        /// <summary>
        /// 执行一个操作，当失败(发生异常)时重试若干次
        /// </summary>
        public static void Execute(this Action action, int attempts = 3, int retryDelay = 0, int timeOut = int.MaxValue)
        {
            action.ThrowIfNull("Action");
            Exception holder = null;
            long start = System.Environment.TickCount;
            while (attempts > 0)
            {
                try
                {
                    action();
                }
                catch (Exception e) { holder = e; }
                if (System.Environment.TickCount - start > timeOut)
                    break;
                Thread.Sleep(retryDelay);
                --attempts;
            }
            if (holder != null)
                throw holder;
        }

        #endregion

        #endregion

        public static object GetMember(this object obj, string member)
        {
            if (obj == null) return null;
            var meminfo = obj.GetType().GetProperty(member, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
            if (meminfo == null) return null;

            return meminfo.GetValue(obj, null);
        }
    }
}
